package com.leyou.order.service;

import com.leyou.common.exception.LyException;
import com.leyou.common.utils.BeanHelper;
import com.leyou.common.utils.IdWorker;
import com.leyou.common.utils.UserHolder;
import com.leyou.item.client.ItemClient;
import com.leyou.item.dto.SkuDTO;
import com.leyou.order.dto.CartFormDTO;
import com.leyou.order.dto.OrderFormDTO;
import com.leyou.order.entity.Order;
import com.leyou.order.entity.OrderDetail;
import com.leyou.order.entity.OrderLogistics;
import com.leyou.order.enums.OrderStatusEnum;
import com.leyou.order.mapper.OrderDetailMapper;
import com.leyou.order.mapper.OrderLogisticsMapper;
import com.leyou.order.mapper.OrderMapper;
import com.leyou.order.utils.PayHelper;
import com.leyou.order.vo.OrderDetailVO;
import com.leyou.order.vo.OrderLogisticsVO;
import com.leyou.order.vo.OrderVO;
import com.leyou.user.client.UserClient;
import com.leyou.user.dto.AddressDTO;
import feign.FeignException;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import tk.mybatis.mapper.entity.Example;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author 虎哥
 */
@Service
public class OrderService {

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private OrderDetailMapper detailMapper;

    @Autowired
    private OrderLogisticsMapper logisticsMapper;

    @Autowired
    private IdWorker idWorker;

    @Autowired
    private ItemClient itemClient;

    @Autowired
    private UserClient userClient;

    @Transactional
    public Long createOrder(OrderFormDTO orderFormDTO) {
        // 1.准备Order数据
        Order order = new Order();
        // 1.1.订单编号
        long orderId = idWorker.nextId();
        order.setOrderId(orderId);
        // 1.2.订单金额相关
        // 1.2.0.将CartDTO集合，转为一个map，key是skuId，值是sku的num
        Map<Long, Integer> skuNunMap = orderFormDTO.getCarts().stream()
                .collect(Collectors.toMap(CartFormDTO::getSkuId, CartFormDTO::getNum));
        // 1.2.1.获取商品id
        List<Long> idList = new ArrayList<>(skuNunMap.keySet());
        // 1.2.2.根据id查询sku的集合
        List<SkuDTO> skuList = itemClient.querySkuByIds(idList);
        // 1.2.3.计算金额总和
        long total = 0;
        if(!CollectionUtils.isEmpty(skuList)){
            for (SkuDTO sku : skuList) {
                // 得到商品数量
                Integer num = skuNunMap.get(sku.getId());
                // 得到单个价格
                Long price = sku.getPrice();
                total += num * price;
            }
        }
        order.setTotalFee(total);
        // 邮费需要结合物流仓库地址、收货人地址、运费模板运算，认为是另一个微服务做的
        order.setPostFee(0L);
        order.setActualFee(order.getTotalFee() + order.getPostFee()/* - 优惠金额*/);
        order.setPaymentType(orderFormDTO.getPaymentType());

        // 1.3.用户
        Long userId = UserHolder.getUser().getId();
        order.setUserId(userId);

        // 1.4.订单状态
        order.setStatus(OrderStatusEnum.INIT.value());

        // 1.5.写入数据库
        orderMapper.insertSelective(order);

        // 2.准备OrderDetail数据
        List<OrderDetail> detailList = buildDetailList(skuList, skuNunMap, orderId);
        detailMapper.insertList(detailList);

        // 3.准备OrderLogistics数据
        // 3.1.获取地址ID
        Long addressId = orderFormDTO.getAddressId();
        // 3.2.根据地址ID查询地址详情
        AddressDTO addressDTO = userClient.queryAddressById(userId, addressId);
        // 3.3.封装成OrderLogistics
        OrderLogistics logistics = BeanHelper.copyProperties(addressDTO, OrderLogistics.class);
        logistics.setOrderId(orderId);
        // 3.4.写入数据库
        logisticsMapper.insertSelective(logistics);

        // 4.减库存
        try {
            itemClient.minusStock(skuNunMap);
        } catch (Exception e) {
            throw new LyException(500, "库存不足！");
        }
        return orderId;
    }

    private List<OrderDetail> buildDetailList(List<SkuDTO> skuList, Map<Long, Integer> skuNunMap, long orderId) {
        List<OrderDetail> list = new ArrayList<>();

        for (SkuDTO sku : skuList) {
            OrderDetail detail = new OrderDetail();
            detail.setTitle(sku.getTitle());
            detail.setSkuId(sku.getId());
            detail.setPrice(sku.getPrice());
            detail.setNum(skuNunMap.get(sku.getId()));
            detail.setOwnSpec(sku.getOwnSpec());
            detail.setImage(StringUtils.substringBefore(sku.getImages(), ","));
            detail.setOrderId(orderId);
            list.add(detail);
        }
        return list;
    }

    public OrderVO queryOrderById(Long orderId) {
        // 1.查询order
        Order order = orderMapper.selectByPrimaryKey(orderId);
        if (order == null) {
            throw new LyException(404, "订单不存在");
        }
        OrderVO orderVO = BeanHelper.copyProperties(order, OrderVO.class);
        // 2.查询OrderDetail
        orderVO.setDetailList(queryDetailByOrderId(orderId));
        // 3.查询OrderLogistics
        orderVO.setLogistics(queryLogisticsByOrderId(orderId));
        return orderVO;
    }

    private OrderLogisticsVO queryLogisticsByOrderId(Long orderId) {
        OrderLogistics logistics = logisticsMapper.selectByPrimaryKey(orderId);
        if (logistics == null) {
            throw new LyException(404, "订单不存在");
        }
        return BeanHelper.copyProperties(logistics, OrderLogisticsVO.class);
    }

    private List<OrderDetailVO> queryDetailByOrderId(Long orderId) {
        OrderDetail record = new OrderDetail();
        record.setOrderId(orderId);
        List<OrderDetail> list = detailMapper.select(record);
        if (CollectionUtils.isEmpty(list)) {
            throw new LyException(404, "订单不存在");
        }
        return BeanHelper.copyWithCollection(list, OrderDetailVO.class);
    }

    @Autowired
    private PayHelper payHelper;

    public String getPayUrl(Long orderId) {
        // 查询订单数据
        Order order = orderMapper.selectByPrimaryKey(orderId);
        if(order == null){
            // 订单不存在
            throw new LyException(400, "订单不存在！");
        }
        // 判断订单的状态
        Integer status = order.getStatus();
        if (!Objects.equals(OrderStatusEnum.INIT.value(), status)) {
            // 已经付款或已经关闭，无需获取url
            throw new LyException(400, "订单已支付或关闭！");
        }
        // 获取支付金额
        Long actualFee = order.getActualFee();
        // 生成支付链接
        return payHelper.unifiedOrder(orderId, actualFee);
    }

    public void handleNotify(Map<String, String> data) {
        // 1.校验支付结果成功或失败
        String resultCode = data.get("result_code");
        if("FAIL".equalsIgnoreCase(resultCode)){
            // 业务失败
            throw new RuntimeException(data.get("err_code_des"));
        }
        // 2.校验签名
        payHelper.isSignatureValid(data);

        // 3.校验订单金额是否一致
        // 3.1.获取返回结果中的订单id和金额
        String out_trade_no = data.get("out_trade_no");
        String total_fee = data.get("total_fee");
        if(StringUtils.isBlank(out_trade_no) || StringUtils.isBlank(total_fee)){
            // 数据有误
            throw new RuntimeException("响应数据有误，订单金额或编号为空！");
        }
        // 3.2.去数据库查询订单
        Order order = orderMapper.selectByPrimaryKey(Long.valueOf(out_trade_no));
        // 3.3.比较金额
        if(!order.getActualFee().toString().equals(total_fee)){
            throw new RuntimeException("响应数据有误，订单金额不匹配！");
        }
        // 4.校验业务幂等性
        if(!Objects.equals(order.getStatus(), OrderStatusEnum.INIT.value())){
            // 订单已经处理过了，重复通知，不处理！
            return;
        }
        // 5.修改订单状态为已支付
        Order record = new Order();
        record.setOrderId(order.getOrderId());
        record.setStatus(OrderStatusEnum.PAY_UP.value());
        record.setPayTime(new Date());

        int count = orderMapper.updateByPrimaryKeySelective(record);
        if(count != 1){
            // 更新失败
            throw new RuntimeException("更新订单状态失败！");
        }
    }

    public Integer queryOrderStatus(Long orderId) {
        // 查询订单
        Order order = orderMapper.selectByPrimaryKey(orderId);
        if(order == null){
            throw new LyException(400, "请求参数有误！订单不存在！");
        }
        return order.getStatus();
    }

    @Transactional
    public void evictOverdueOrder(Date deadline){
        // 1.查询超时未支付订单（status=1，create_time < deadline)
        Example example = new Example(Order.class);
        example.createCriteria()
                .andEqualTo("status", OrderStatusEnum.INIT.value())
                .andLessThanOrEqualTo("createTime", deadline);
        List<Order> orders = orderMapper.selectByExample(example);
        if(CollectionUtils.isEmpty(orders)){
            return;
        }

        List<Long> orderIdList = orders.stream().map(Order::getOrderId).collect(Collectors.toList());
        // 2.修改订单状态为已经关闭
        // 2.1.更新的内容
        Order record = new Order();
        record.setStatus(OrderStatusEnum.CLOSED.value());
        record.setCloseTime(new Date());
        // 2.2.更新的条件
        example = new Example(Order.class);
        example.createCriteria().andIn("orderId", orderIdList);
        orderMapper.updateByExampleSelective(record, example);

        // 3.查询订单详情
        example = new Example(OrderDetail.class);
        example.createCriteria().andIn("orderId", orderIdList);
        List<OrderDetail> detailList = detailMapper.selectByExample(example);

        // 4.提取出商品skuId和num，存入map，key是skuId，value是num
        Map<Long, Integer> skuMap = detailList.stream()
                .collect(Collectors.groupingBy(OrderDetail::getSkuId, Collectors.summingInt(OrderDetail::getNum)));
        // 5.恢复库存
        try {
            itemClient.plusStock(skuMap);
        }catch (FeignException e){
            throw new LyException(e.status(), e.contentUTF8());
        }
    }
}
